package com.erpoa.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;

public class ThreadLocalHelper {

    private static Logger logger = LoggerFactory
            .getLogger(ThreadLocalHelper.class);

    public static void clearThreadLocal() {
        String[] clzz = null;
        String clearThreadLocal = (String) PropertiesHelper.getPropery("clear.threadlocal");
        if (clearThreadLocal != null) {
            clzz = clearThreadLocal.split(",");
        } else {
            clzz = new String[]{};
        }
        clearThreadLocal(clzz);
    }

    public static void clearThreadLocal(String[] clzz) {
        try {
            // 获取当前线程
            Thread currentThread = Thread.currentThread();

            // 获取threadLocals
            Field threadLocalField = currentThread.getClass().getDeclaredField(
                    "threadLocals");
            threadLocalField.setAccessible(true);
            Object threadLocalMap = threadLocalField.get(currentThread);
            if (threadLocalMap == null) {
                return;
            }

            // 清除threadLocals中保存的弱引用
            Class<? extends Object> threadLocalMapClz = threadLocalMap
                    .getClass();
            Field threadLocalMapTableField = threadLocalMapClz
                    .getDeclaredField("table");
            threadLocalMapTableField.setAccessible(true);
            Object table = threadLocalMapTableField.get(threadLocalMap);
            if (table instanceof Reference[]) {
                WeakReference<?>[] entries = ((WeakReference<?>[]) table);
                for (int i = (entries.length - 1); i >= 0; i--) {
                    WeakReference<?> entry = entries[i];
                    if (entry != null) {
                        if (clzz.length == 0) {
                            entry.clear();
                        } else {
                            Object threadLocal = entry.get();
                            if (threadLocal != null
                                    && threadLocal instanceof ThreadLocal) {
                                @SuppressWarnings("rawtypes")
                                Object threadLocalValue = ((ThreadLocal) threadLocal)
                                        .get();
                                String threadLocalValueClz = threadLocalValue
                                        .getClass().getName();
                                for (String clz : clzz) {
                                    if (threadLocalValueClz.contains(clz)) {
                                        entry.clear();
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            logger.debug("清除当前线程绑定数据(ThreadLocal).");
        }
    }

    public static void clearInheritableThreadLocal() {
        String[] clzz = null;
        String clearThreadLocal = (String) PropertiesHelper.getPropery("clear.inheritablethreadlocal");
        if (clearThreadLocal != null) {
            clzz = clearThreadLocal.split(",");
        } else {
            clzz = new String[]{};
        }
        clearInheritableThreadLocal(clzz);
    }

    public static void clearInheritableThreadLocal(String[] clzz) {
        try {
            // 获取当前线程
            Thread currentThread = Thread.currentThread();

            // 获取inheritableThreadLocals
            Field threadLocalField = currentThread.getClass().getDeclaredField(
                    "inheritableThreadLocals");
            threadLocalField.setAccessible(true);
            Object threadLocalMap = threadLocalField.get(currentThread);
            if (threadLocalMap == null) {
                return;
            }

            // 清除inheritableThreadLocals中保存的弱引用
            Class<? extends Object> threadLocalMapClz = threadLocalMap
                    .getClass();
            Field threadLocalMapTableField = threadLocalMapClz
                    .getDeclaredField("table");
            threadLocalMapTableField.setAccessible(true);
            Object table = threadLocalMapTableField.get(threadLocalMap);
            if (table != null) {
                if (table instanceof WeakReference[]) {
                    WeakReference<?>[] entries = ((WeakReference<?>[]) table);
                    for (int i = (entries.length - 1); i >= 0; i--) {
                        WeakReference<?> entry = entries[i];
                        if (entry != null) {
                            if (clzz.length == 0) {
                                entry.clear();
                            } else {
                                Object threadLocal = entry.get();
                                if (threadLocal != null
                                        && threadLocal instanceof ThreadLocal) {
                                    @SuppressWarnings("rawtypes")
                                    Object threadLocalValue = ((ThreadLocal) threadLocal)
                                            .get();
                                    String threadLocalValueClz = threadLocalValue
                                            .getClass().getName();
                                    for (String clz : clzz) {
                                        if (threadLocalValueClz.contains(clz)) {
                                            entry.clear();
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            logger.debug("清除当前线程绑定数据(InheritableThreadLocal).");
        }
    }
}
